package com.shift.sdk;

import java.io.IOException;

import com.shift.sdk.R;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.Size;
import android.provider.MediaStore;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;

/**
 * カメラプレビュー(静止画撮影)
 *
 * @author SHIFT
 */
public class PicturePreview extends SurfaceView implements SurfaceHolder.Callback, PictureCallback,
        AutoFocusCallback {

    /**
     * サーフェイスホルダー.
     */
    private SurfaceHolder holder;

    /**
     * カメラ.
     */
    protected Camera mCamera;

    /**
     * コンテキスト(アクティビティ).
     */
    private Context context;

    /**
     * コンストラクタ.
     *
     * @param context
     *            コンテキスト
     * @param attrs
     */
    public PicturePreview(Context context, AttributeSet attrs) {
        super(context, attrs);
        holder = getHolder();
        holder.addCallback(this);
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        this.context = context;
    }

    /**
     * サーフェイスビュー生成時の処理
     */
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        try {
            mCamera = Camera.open();
            mCamera.setPreviewDisplay(holder);

        } catch (IOException e) {

            if (mCamera != null) {
                mCamera.release();
                mCamera = null;
            }
            Log.e(context.getPackageName(), e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * ビューが変化した際の処理.
     */
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

        // プレビュー停止
        mCamera.stopPreview();
        // カメラ情報取得
        Parameters mParam = mCamera.getParameters();

        // カメラの向きを縦に設定
        int previewWidth = height;
        int previewHeight = width;
        mCamera.setDisplayOrientation(90);

        // カメラがサポートするプレビューサイズを取得
        int tmpWidth = 0;
        int tmpHeight = 0;
        for (Size size : mParam.getSupportedPreviewSizes()) {
            Log.d("CAMERA", "サポートサイズ:w=" + size.width + "/h=" + size.height);
            if (size.width > previewWidth || size.height > previewHeight) {
                continue;
            }

            if (tmpWidth <= size.width) {
                if (tmpHeight < size.height) {
                    tmpWidth = size.width;
                    tmpHeight = size.height;
                }
            }
        }
        previewWidth = tmpWidth;
        previewHeight = tmpHeight;

        Log.d("CAMERA", "カメラ設定サイズ：w=" + previewWidth + "/h=" + previewHeight);
        // プレビューサイズをカメラのパラメータにセット
        mParam.setPreviewSize(previewWidth, previewHeight);
        mCamera.setParameters(mParam);

        // ビューのサイズをカメラのプレビューサイズに合わせて変更
        ViewGroup.LayoutParams layoutParams = getLayoutParams();
        layoutParams.height = previewWidth;
        layoutParams.width = previewHeight;
        setLayoutParams(layoutParams);

        // プレビュー開始
        mCamera.startPreview();
    }

    /**
     * サーフェイスビュー破棄時の処理.
     */
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        if (mCamera != null) {
            mCamera.stopPreview();
            mCamera.release();
        }
    }

    /**
     * カメラ撮影
     */
    public void takePicture() {
        // オートフォーカスでカメラ撮影
        mCamera.autoFocus(this);
    }

    /**
     * スケールを取得する
     *
     * @param data
     *            縮尺を調査する画像データ
     * @param width
     *            変更する横のサイズ
     * @param height
     *            変更する縦のサイズ
     * @return 変更したいサイズのスケールの値
     */
    public int getScale(byte[] data, int width, int height) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeByteArray(data, 0, data.length, options);

        int scaleW = options.outWidth / width + 1;
        int scaleH = options.outHeight / height + 1;

        int scale = Math.max(scaleW, scaleH);
        options.inJustDecodeBounds = false;
        return scale;
    }

    /**
     * オートフォーカス.
     */
    @Override
    public void onAutoFocus(boolean success, Camera camera) {
        // カメラ撮影
        camera.takePicture(null, null, this);
    }

    /**
     * カメラ撮影.
     */
    @Override
    public void onPictureTaken(byte[] data, Camera camera) {

        // OutOfMemory防止のため、画像サイズを調整
        int scale = getScale(data, this.getWidth(), this.getHeight());

        // Bitmap生成時のオプションを作成
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = scale;

        // カメラ画像からスケールの値を設定した状態でカメラ画像をBitmap形式で格納
        Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options);

        // 縦向きに回転させる
        Matrix matrix = new Matrix();
        matrix.postRotate(90);
        Bitmap convertedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
                bitmap.getHeight(), matrix, true);

        // ギャラリーに保存
        MediaStore.Images.Media.insertImage(
                context.getContentResolver(),
                convertedBitmap, null, null);

        ((PictureActivity) context).setOriginalBitmap(convertedBitmap.copy(Config.ARGB_8888, true));

        // イメージビューに撮影した画像を設定
        ImageView view = (ImageView) ((Activity) context).findViewById(R.id.image_select);
        view.setImageBitmap(convertedBitmap);
        view.setVisibility(View.VISIBLE);
        ((Activity) context).findViewById(R.id.button_analyze).setVisibility(View.VISIBLE);
        setVisibility(View.GONE);
        ((Activity) context).findViewById(R.id.image_empty).setVisibility(View.GONE);
    }
}
